﻿using System;
using System.Collections;
using System.Web.UI;

namespace Trentacular.SharePoint.Features.Web.UI.WebControls
{
    public class DelegateDataSource : DataSourceControl
    {
        public bool CanPage { get; set; }
        public bool CanRetrieveTotalRowCount { get; set; }

        private bool _canSort;
        public bool CanSort
        {
            get
            {
                if (AutoSort) return true;
                return _canSort;
            }
            set { _canSort = value; }
        }

        /// <summary>
        /// If true, the results of the ExecuteSelect operation will
        /// automatically be sorted based on the SortExpression, assuming
        /// the SortExpression corresponds to a Property name.  Setting
        /// AutoSort to true implies CanSort is true.
        /// </summary>
        public bool AutoSort { get; set; }

        public event Select Select;
        public event Insert Insert;
        public event Update Update;
        public event Delete Delete;

        private DelegateDataSourceView _view;
        public DelegateDataSourceView View
        {
            get
            {
                if (_view == null)
                    _view = new DelegateDataSourceView(this);
                return _view;
            }
        }

        protected override DataSourceView GetView(string viewName)
        {
            return View;
        }

        public virtual IEnumerable OnSelect(DataSourceSelectArguments args)
        {
            if (Select == null)
                throw new InvalidOperationException(
                    string.Format(
                        "Missing Select delegate on DelegateDataSource control '{0}'.  Please specify the delegate method to perform the select operation.",
                        ID
                        )
                    );

            var selectArgs = new DelegateSelectArguments(args);
            Select(selectArgs);
            return selectArgs.Results;
        }

        public virtual int OnInsert(IDictionary values)
        {
            if (Insert == null)
                throw new InvalidOperationException(
                    string.Format(
                        "Missing Insert delegate on DelegateDataSource control '{0}'.  Please specify the delegate method to perform the insert operation.",
                        ID
                        )
                    );

            var insertArgs = new DelegateInsertArguments(values);
            Insert(insertArgs);
            return insertArgs.ResultCount;
        }

        public virtual int OnUpdate(IDictionary keys, IDictionary values, IDictionary oldValues)
        {
            if (Update == null)
                throw new InvalidOperationException(
                    string.Format(
                        "Missing Update delegate on DelegateDataSource control '{0}'.  Please specify the delegate method to perform the update operation.",
                        ID
                        )
                    );

            var updateArgs = new DelegateUpdateArguments(keys, values, oldValues);
            Update(updateArgs);
            return updateArgs.ResultCount;
        }

        public virtual int OnDelete(IDictionary keys, IDictionary oldValues)
        {
            if (Delete == null)
                throw new InvalidOperationException(
                    string.Format(
                        "Missing Delete delegate on DelegateDataSource control '{0}'.  Please specify the delegate method to perform the delete operation.",
                        ID
                        )
                    );

            var deleteArgs = new DelegateDeleteArguments(keys, oldValues);
            Delete(deleteArgs);
            return deleteArgs.ResultCount;
        }
    }

    public delegate void Select(DelegateSelectArguments args);
    public delegate void Insert(DelegateInsertArguments args);
    public delegate void Update(DelegateUpdateArguments args);
    public delegate void Delete(DelegateDeleteArguments args);

    public class DelegateSelectArguments
    {
        public DelegateSelectArguments(DataSourceSelectArguments args)
        {
            Arguments = args;
        }

        public DataSourceSelectArguments Arguments { get; private set; }
        public IEnumerable Results { get; set; }
    }

    public class DelegateInsertArguments
    {
        public DelegateInsertArguments(IDictionary values)
        {
            Values = values;
        }

        public IDictionary Values { get; private set; }
        public int ResultCount { get; set; }
    }

    public class DelegateUpdateArguments
    {
        public DelegateUpdateArguments(IDictionary keys, IDictionary values, IDictionary oldValues)
        {
            Keys = keys;
            Values = values;
            OldValues = oldValues;
        }

        public IDictionary Keys { get; private set; }
        public IDictionary Values { get; private set; }
        public IDictionary OldValues { get; private set; }
        public int ResultCount { get; set; }
    }

    public class DelegateDeleteArguments
    {
        public DelegateDeleteArguments(IDictionary keys, IDictionary oldValues)
        {
            Keys = keys;
            OldValues = oldValues;
        }

        public IDictionary Keys { get; private set; }
        public IDictionary OldValues { get; private set; }
        public int ResultCount { get; set; }
    }
}
